package com.ly.fn.biz.ins.srv.api.processor;

import com.google.common.collect.Lists;
import com.ly.fn.biz.ins.srv.api.common.ServiceConfig;
import com.ly.fn.biz.ins.srv.api.register.InsServiceClassPathBeanDefinitionScanner;
import com.ly.fn.biz.ins.srv.api.util.ASMUtil;
import com.ly.fn.biz.ins.srv.api.util.DynamicClassLoader;
import com.ly.fn.biz.ins.srv.api.util.JavassistUtil;
import com.ly.fn.inf.disconf.client.core.common.utils.ClassLoaderUtil;
import com.ly.fn.inf.ttl.TtlRemoteJob;
import com.ly.fn.inf.xpro.plugin.api.RemoteObjectFactoryAware;
import com.ly.fn.inf.xpro.plugin.core.ApplicationReadyListener;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @Author xiaoyuan.wang
 * @Date 2021/9/27 10:42
 * @Version 1.0
 */
public class ControllerProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, ApplicationContextAware {

    public ControllerProcessor(String packageName) {
        this.packageName = packageName + ".controller";
    }

    private String packageName;
    private ConfigurableEnvironment environment;
    private ResourceLoader resourceLoader;

    private ApplicationContext applicationContext;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment) environment;
    }


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }


    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        InsServiceClassPathBeanDefinitionScanner scanner = new InsServiceClassPathBeanDefinitionScanner(registry, this.environment, this.resourceLoader);
        String scanPackage = ServiceConfig.instance.getBasePackage();
        Set<Class> classSet = scanner.findFacadeService(scanPackage);
        Map<Class, List<Class>> serviceGroup = this.genServiceGroup(classSet);
        for (Class clzInterface : serviceGroup.keySet()) {
            try {
                //排查 org.springframework 框架级别的变量
                List<Class> srvList = serviceGroup.get(clzInterface);
                boolean dealQualifier = srvList.size() > 1;
                for (Class clz : srvList) {
                    String ctlName = getClassName(clzInterface, clz, dealQualifier);
                    String qualifierName = dealQualifier ? StringUtils.uncapitalize(clz.getSimpleName()) : null;
                    String controllerName = ctlName + "Controller";
                    Class controllerClz = JavassistUtil.toControllerClass(this.packageName + "." + controllerName, clzInterface, qualifierName);
                    RootBeanDefinition beanDefinition = new RootBeanDefinition(controllerClz);
                    registry.registerBeanDefinition(controllerClz.getName(), beanDefinition);
                }
            } catch (Exception e) {
                System.out.println("service to controller failed: " + e);
            }
        }



        //根据Term生成Controller类
        Set<Class> termServices = scanner.findTermService(scanPackage);
        for (Class termService : termServices) {
            try {
                Class controllerClz = JavassistUtil.termToControllerClass(packageName, termService);

                //Class<?> controllerClz = ASMUtil.generateTermService2Controller(packageName, termService);

                RootBeanDefinition beanDefinition = new RootBeanDefinition(controllerClz);
                registry.registerBeanDefinition(controllerClz.getName(), beanDefinition);
            } catch (Exception e) {
                System.out.println("term to controller failed. " + e);
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private Map<Class, List<Class>> genServiceGroup(Set<Class> classSet) {
        Map<Class, List<Class>> interfaceSrvMap = new HashMap();
        for (Class clz : classSet) {
            Class[] interfaces = clz.getInterfaces();
            if (interfaces.length > 0) {
                Class mapKey = interfaces[0];
                List<String> igronList = Lists.newArrayList(
                        TtlRemoteJob.class.getSimpleName(),
                        RemoteObjectFactoryAware.class.getSimpleName(),
                        InitializingBean.class.getSimpleName(),
                        ApplicationContextAware.class.getSimpleName(),
                        ApplicationReadyListener.class.getSimpleName()
                );

                if(igronList.contains(mapKey.getSimpleName())){
                    continue;
                }
                List<Class> srvList = interfaceSrvMap.getOrDefault(mapKey, Lists.newArrayList());
                srvList.add(clz);
                interfaceSrvMap.put(mapKey, srvList);
            }
        }
        return interfaceSrvMap;
    }
    private static String getClassName(Class interfaceClz, Class srvClz, boolean dealQualifier) {
        String controllerName = "";
        String name = dealQualifier ? srvClz.getSimpleName() : interfaceClz.getSimpleName();
        if (name.endsWith("Service")) {
            name = name.substring(0, name.lastIndexOf("Service"));
        }

        if (name.startsWith("I")) {
            controllerName = name.substring(1, name.length());
        } else {
            controllerName = name;
        }

        return controllerName;
    }
}